package com.acme.mock;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import com.acme.bankapp.domain.bank.Bank;
import com.acme.bankapp.domain.bank.Client;
import com.acme.bankapp.exceptions.ClientExistsException;
import com.acme.bankapp.service.bank.BankDataLoaderService;
import com.acme.bankapp.service.bank.BankService;
import com.acme.bankapp.service.bank.ParseFeedFileException;

public class BankServer {
	static final String MES_INVALID_DATA = "Data received in unknown format";

	static final String CMD_ADD = "add";
	static final String CMD_GET_INFO = "get_info";
	static final String CMD_BYE = "bye";
	
	static final String RESP_BYE = "bye";
	static final String RESP_INVALID = "invalid data";

	private static final String CMD_DELINMIER = " ";

	private static final String RESP_SUCCESS = "Client is added successfully";
	
	ServerSocket providerSocket;
	Socket connection = null;
	ObjectOutputStream out;
	ObjectInputStream in;
	String message;
	
	Bank bank;

	BankServer(Bank bank) {
		this.bank = bank;
	}

	void run() {
		try {
			// 1. creating a server socket
			providerSocket = new ServerSocket(2004, 10);
			// 2. Wait for connection
			System.out.println("Waiting for connection");
			connection = providerSocket.accept();
			System.out.println("Connection received from "
					+ connection.getInetAddress().getHostName());
			// 3. get Input and Output streams
			out = new ObjectOutputStream(connection.getOutputStream());
			out.flush();
			in = new ObjectInputStream(connection.getInputStream());
			sendMessage("Connection successful");
			// 4. The two parts communicate via the input and output streams
			do {
				try {
					message = (String)in.readObject();
				} catch (ClassNotFoundException classnot) {
					System.err.println(MES_INVALID_DATA);
				}
				
				message = parseMessage(message);
				
				sendMessage(message);
			} while (!message.equals(RESP_BYE));
		} catch (IOException ioException) {
			ioException.printStackTrace();
		} finally {
			// 4: Closing connection
			try {
				in.close();
				out.close();
				providerSocket.close();
			} catch (IOException ioException) {
				ioException.printStackTrace();
			}
		}
	}

	private String parseMessage(String message) {
		System.out.println("client>" + message);
		String[] parts = message.split(CMD_DELINMIER);
		String cmd = parts[0];
		switch (cmd) {
		case CMD_ADD:
			if (parts.length > 1) {			
				try {
					Client client = BankDataLoaderService.parseClient(parts[1]);
					BankService.addClient(bank, client);					
					return RESP_SUCCESS;
				} catch (ParseFeedFileException e) {
					return e.getMessage();
				} catch (IllegalArgumentException e) {
					return e.getMessage();
				} catch (ClientExistsException e) {
					return e.getMessage();
				}
			}
			else
				return RESP_INVALID;
		case CMD_BYE:
			return RESP_BYE;
		default:
			return RESP_INVALID;
		}
	}

	void sendMessage(final String msg) {
		try {
			out.writeObject(msg);
			out.flush();
			System.out.println("server>" + msg);
		} catch (IOException ioException) {
			ioException.printStackTrace();
		}
	}

	public static void startServer(Bank bank) {
		BankServer server = new BankServer(bank);
		while (true) {
			server.run();
		}
	}
}
